package com.syp.auth.export.support.client;

import java.util.List;

import org.apache.http.HttpHost;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;

/**
 * poolingHttpClient
 */
public class PoolingHttpClientFactoryBean implements FactoryBean<HttpClient>, DisposableBean {

	private static int DEFAULT_HTTP_PORT = 80;

	public static int DEFAULT_CONNECT_TIMEOUT = 1000 * 60;
	public static int DEFAULT_REQUEST_TIMEOUT = 1000 * 60;
	public static int DEFAULT_SOCKET_TIMEOUT = 1000 * 60;

	public static int DEFAULT_PERHOST_MAX_CONNECTIONS = 1000;
	public static int DEFAULT_MAX_CONNECTIONS = 8000;

	private int connectTimeout = DEFAULT_CONNECT_TIMEOUT;
	private int connectionRequestTimeout = DEFAULT_REQUEST_TIMEOUT;
	private int socketTimeout = DEFAULT_SOCKET_TIMEOUT;
	private int maxTotal = DEFAULT_MAX_CONNECTIONS;
	private int maxPerRoute = DEFAULT_MAX_CONNECTIONS;

	private List<String> httpHostConfigs;

	private RequestConfig config;
	private PoolingHttpClientConnectionManager cm;

	@Override
	public HttpClient getObject() throws Exception {
		config = RequestConfig.custom().setConnectTimeout(connectTimeout).setConnectionRequestTimeout(connectionRequestTimeout).setSocketTimeout(socketTimeout).build();
		cm = new PoolingHttpClientConnectionManager();
		cm.setMaxTotal(maxTotal);
		cm.setDefaultMaxPerRoute(maxPerRoute);
		if (httpHostConfigs != null && httpHostConfigs.size() > 0) {
			for (String httpHostConfig : httpHostConfigs) {
				String[] hostConfigs = httpHostConfig.split(",");

				if (hostConfigs.length < 3)
					throw new RuntimeException("HttpClient4 httpHostConfigs error!!!");

				int _port;
				try {
					_port = Integer.parseInt(hostConfigs[1]);
				} catch (NumberFormatException e) {
					_port = DEFAULT_HTTP_PORT;
				}

				int _perhostMaxConnection;
				try {
					_perhostMaxConnection = Integer.parseInt(hostConfigs[2]);
				} catch (NumberFormatException e) {
					_perhostMaxConnection = DEFAULT_PERHOST_MAX_CONNECTIONS;
				}

				HttpHost _httpHost = new HttpHost(hostConfigs[0], _port);

				cm.setMaxPerRoute(new HttpRoute(_httpHost), _perhostMaxConnection);
				cm.setDefaultMaxPerRoute(_perhostMaxConnection);
			}
		}
		return HttpClients.custom().setConnectionManager(cm).setDefaultRequestConfig(config).build();
	}

	@Override
	public Class<?> getObjectType() {		
		return HttpClient.class;
	}

	@Override
	public boolean isSingleton() {
		return false;
	}

	@Override
	public void destroy() throws Exception {
		cm.shutdown();
	}

	public int getConnectTimeout() {
		return connectTimeout;
	}

	public void setConnectTimeout(Integer connectTimeout) {
		if (connectTimeout != null) {
			this.connectTimeout = connectTimeout;
		}
	}

	public int getConnectionRequestTimeout() {
		return connectionRequestTimeout;
	}

	public void setConnectionRequestTimeout(Integer connectionRequestTimeout) {
		if (connectionRequestTimeout != null) {
			this.connectionRequestTimeout = connectionRequestTimeout;
		}
	}

	public int getSocketTimeout() {
		return socketTimeout;
	}

	public void setSocketTimeout(Integer socketTimeout) {
		if (socketTimeout != null) {
			this.socketTimeout = socketTimeout;
		}
	}

	public int getMaxTotal() {
		return maxTotal;
	}

	public void setMaxTotal(Integer maxTotal) {
		if (maxTotal != null) {
			this.maxTotal = maxTotal;
		}
	}

	public int getMaxPerRoute() {
		return maxPerRoute;
	}

	public void setMaxPerRoute(Integer maxPerRoute) {
		if (maxPerRoute != null) {
			this.maxPerRoute = maxPerRoute;
		}
	}

	public List<String> getHttpHostConfigs() {
		return httpHostConfigs;
	}

	public void setHttpHostConfigs(List<String> httpHostConfigs) {
		this.httpHostConfigs = httpHostConfigs;
	}

}
